package com.zhenyi.youqu.api;

import java.util.Date;
import java.util.Map;

import com.cenjiawen.common.IndexController;
import com.cjw.model.DBMap;
import com.jfinal.aop.Before;
import com.jfinal.aop.Clear;
import com.jfinal.kit.HttpKit;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.DbPro;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.jfinal.weixin.sdk.kit.PaymentKit;
import com.utils.PathUtils;
import com.wxpay.utils.MD5Util;
import com.youqu.common.model.YqApp;
import com.youqu.common.model.YqOrder;
import com.zhenyi.xhc.core.aes.Encrypt;
import com.zhenyi.youqu.core.OrderHandler;
import com.zhenyi.youqu.interceptor.YQSignInterceptor;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;

public class BillController extends IndexController {

	// protected final String APP_ID = PropKit.get("YQ_APP_ID", "");
	// protected final String APP_SECRET = PropKit.get("YQ_APP_SECRET", "");
	// protected final String PARTNER = PropKit.get("YQ_PARTNER", "");
	// protected final String NOTIFY_URL = PropKit.get("YQ_NOTIFY_URL", "");
	// protected final String PARTNER_KEY = PropKit.get("YQ_PARTNER_KEY", "");
	// protected final String REFUND_NOTIFY_URL =
	// PropKit.get("YQ_REFUND_NOTIFY_URL", "");
	// protected final String SSL_PATH = PathUtils.getFile("cert", APP_ID,
	// "apiclient_cert.p12");
	protected DbPro db = Db.use("youqu");

	@Before(YQSignInterceptor.class)
	public void updateOrderData() {
		String outTradeNo = getPara("outTradeNo");
		String data = getPara("data");
		if (StrKit.isBlank(outTradeNo) || StrKit.isBlank(data)) {
			renderFailure();
			return;
		}
		YqOrder order = YqOrder.dao.searchFirst("out_trade_no", outTradeNo);
		if (order == null) {
			renderError(404);
			return;
		}
		order.setData(data);
		renderFlag(order.update());
	}

	@Clear
	@Before(Tx.class)
	public void billPush() {
		String xmlResult = HttpKit.readData(getRequest());
		if (StrKit.isBlank(xmlResult)) {
			System.out.println("no xmlResult");
			renderFailure("no xmlResult");
			renderPayFail();
			return;
		}
		if (DEBUG) {
			System.out.println(xmlResult);
		}
		Map<String, String> result = PaymentKit.xmlToMap(xmlResult);

		Long appId = getParaToLong(0);
		YqApp app = YqApp.dao.findByAppId(appId);

		// String partnerKey = PARTNER_KEY;
		String partnerKey = app.getWechatPartnerKey();

		String sign = result.get("sign");
		String mySign = PaymentKit.createSign(result, partnerKey);
		if (!mySign.equals(sign)) {
			// order.setVerify(1);
			LogKit.info("sign error");
			LogKit.info("sign " + sign);
			LogKit.info("mySign " + mySign);
			System.out.println(xmlResult);
			// renderPayFail();
			// return;
		} else {
			// order.setVerify(0);
		}

		// String appid = result.get("appid");
		String bank_type = result.get("bank_type");
		String cash_fee = result.get("cash_fee");
		String fee_type = result.get("fee_type");
		String is_subscribe = result.get("is_subscribe");
		// String mch_id = result.get("mch_id");
		// String nonce_str = result.get("nonce_str");
		String openid = result.get("openid");
		String out_trade_no = result.get("out_trade_no");
		String result_code = result.get("result_code");
		String return_code = result.get("return_code");
		String time_end = result.get("time_end");
		String total_fee = result.get("total_fee");
		String trade_type = result.get("trade_type");
		String transaction_id = result.get("transaction_id");

		// String attach = result.get("attach");
		if (!"SUCCESS".equals(return_code)) {
			LogKit.warn("返回失败 " + out_trade_no);
			LogKit.warn(xmlResult);
			renderPaySuccess();
			return;
		}
		if (!"SUCCESS".equals(result_code)) {
			LogKit.warn("支付结果失败 " + out_trade_no);
			LogKit.warn(xmlResult);
			renderPaySuccess();
			return;
		}
		renderPaySuccess();
		// System.out.println(JsonKit.toJson(result));
		// System.out.println("--------");
		// System.out.println(JsonKit.toJson(result));
		// System.out.println("out_trade_no: " + out_trade_no);
		// System.out.println("total_fee: " + total_fee);
		// System.out.println("cash_fee: " + cash_fee);
		// System.out.println("out_trade_no: " + out_trade_no);
		// System.out.println("--------");

		// long id = hashids.decode(out_trade_no)[0];
		YqOrder order = YqOrder.dao.searchFirst("out_trade_no", out_trade_no);
		if (order == null) {
			LogKit.warn("no order no " + out_trade_no);
			return;
		}
		order.setOpenid(openid);

		order.setPaidTime(new Date());
		order.setBankType(bank_type);
		order.setIsSubscribe(is_subscribe);
		order.setTradeType(trade_type);
		order.setTransactionId(transaction_id);
		order.setFeeType(fee_type);
		order.setTimeEnd(time_end);
		order.setCashFee(cash_fee);
		order.setPaid(Integer.parseInt(total_fee));
		order.update();
		order.updateOrderStatus();
		renderPaySuccess();

		try {
			new OrderHandler().onSuccess(order);
			// onSuccess(order);
		} catch (Exception e) {
			LogKit.warn("支付完成处理", e);
		}
		sendNoti(order);
	}

	private FileWriter fileWriter = new FileWriter(
			PathUtils.getFile("logs", "youqu", "api", "noti", DateUtil.today() + ".txt"));

	/**
	 * 支付通知回调
	 * 
	 * @param order
	 */
	private void sendNoti(YqOrder order) {
		String url = order.getNotifyUrl();
		if (StrKit.isBlank(url)) {
			return;
		}
		if (!url.contains("http://") && !url.contains("https://")) {
			return;
		}
		new Thread(new Runnable() {
			public void run() {
				DBMap map = order.getResponseData();
				map.put("paid", order.getPaid());
				map.put("total", order.getTotalFee());
				map.put("openid", order.getOpenid());
				String json = JsonKit.toJson(map);
				HttpRequest reuqest = HttpUtil.createPost(url);
				reuqest.body(json);
				HttpResponse response = reuqest.execute();
				if (response.getStatus() == 200) {
					order.setIsNoti(1);
					order.update();
					fileWriter.append(DateUtil.now() + "\t" + url + "\tsuc");
					return;
				} else {
					fileWriter.append(DateUtil.now() + "\t" + url + "\tfial");
				}
				ThreadUtil.safeSleep(5000);
				response = reuqest.execute();
				if (response.getStatus() == 200) {
					order.setIsNoti(1);
					order.update();
					fileWriter.append(DateUtil.now() + "\t" + url + "\tsuc");
					return;
				} else {
					fileWriter.append(DateUtil.now() + "\t" + url + "\tfial");
				}
				ThreadUtil.safeSleep(30000);
				response = reuqest.execute();
				if (response.getStatus() == 200) {
					order.setIsNoti(1);
					order.update();
					fileWriter.append(DateUtil.now() + "\t" + url + "\tsuc");
					return;
				} else {
					fileWriter.append(DateUtil.now() + "\t" + url + "\tfial");
				}
			}
		}).start();
	}

	@Clear
	@Before(Tx.class)
	public void billRefund() {
		String xmlResult = HttpKit.readData(getRequest());
		if (StrKit.isBlank(xmlResult)) {
			renderFailure("no xmlResult");
			renderPayFail();
			return;
		}
		// if (DEBUG) {
		// LogKit.info(xmlResult);
		// }
		Map<String, String> result = PaymentKit.xmlToMap(xmlResult);
		// String result_code = result.get("result_code");
		String return_code = result.get("return_code");
		if (!"SUCCESS".equals(return_code)) {
			LogKit.warn("返回失败");
			renderPayFail();
			return;
		}

		String req_info = result.get("req_info");

		Long appId = getParaToLong(0);
		YqApp app = YqApp.dao.findByAppId(appId);
		String partnerKey = app.getWechatPartnerKey();

		Map<String, String> refundResult = getDeResult(req_info, partnerKey);
		String refund_status = refundResult.get("refund_status");
		if (!"SUCCESS".equals(refund_status)) {
			renderPaySuccess();
			return;
		}
		String out_trade_no = refundResult.get("out_trade_no");
		YqOrder order = YqOrder.dao.searchFirst("out_trade_no", out_trade_no);
		order.setRefundTime(new Date());
		order.update();
		order.updateOrderStatus();
		order.updateOrderInfo();
		renderPaySuccess();
	}

	private Map<String, String> getDeResult(String en, String PARTNER_KEY) {
		String key = MD5Util.MD5Encode(PARTNER_KEY, "utf-8");
		String de = Encrypt.Aes256Decode(Base64.decode(en), key.getBytes());
		Map<String, String> result = PaymentKit.xmlToMap(de);
		return result;
	}

	private void renderPayFail() {
		String returnXML = "<xml>\n" + "<return_code><![CDATA[FAIL]]></return_code>\n"
				+ "<return_msg><![CDATA[FAIL]]></return_msg>\n" + "</xml>";
		renderText(returnXML, "text/xml");
	}

	private void renderPaySuccess() {
		String returnXML = "<xml>\n" + "<return_code><![CDATA[SUCCESS]]></return_code>\n"
				+ "<return_msg><![CDATA[OK]]></return_msg>\n" + "</xml>";
		renderText(returnXML, "text/xml");
	}
}
